/*
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 */

package com.ecarx.systemui.plugin.controller;

import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
import static android.media.AudioManager.ADJUST_MUTE;
import static android.media.AudioManager.ADJUST_UNMUTE;
import static android.media.AudioManager.STREAM_VOICE_CALL;
import static android.media.AudioSystem.STREAM_ASSISTANT;
import static android.media.AudioSystem.STREAM_MUSIC;
import static android.media.AudioSystem.STREAM_NAVI_TTS;
import android.annotation.SuppressLint;
import android.car.Car;
import android.car.media.CarAudioManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.IVolumeController;
import android.os.IBinder;
import android.os.RemoteException;

import com.ecarx.systemui.plugin.utils.LogUtils;
import com.ecarx.systemui.plugin.PluginContext;

import java.util.ArrayList;
import java.util.List;

public class CarVoiceController {

    private static final String TAG = "CarVoiceControllerTag";
    private static CarVoiceController mCarVoiceController;
    private Car mCar;
    private CarAudioManager mCarAudioManager;
    private List<Integer> mAudioSource;
    private IOnVolumeChanged mListener;

    private int MEDIA_GROUP_ID = -1;
    private int NAVI_GROUP_ID = -1;
    private int VOICE_GROUP_ID = -1;
    private int PHONE_GROUP_ID = -1;

    private int MEDIA_MAX_VOLUME = 0;
    private int NAVI_MAX_VOLUME = 0;
    private int VOICE_MAX_VOLUME = 0;
    private int PHONE_MAX_VOLUME = 0;

    public int getMediaGroupId() {
        LogUtils.d(TAG, "getMediaGroupId MEDIA_GROUP_ID:" + MEDIA_GROUP_ID);
        return MEDIA_GROUP_ID;
    }

    public int getNaviGroupId() {
        LogUtils.d(TAG, "getNaviGroupId NAVI_GROUP_ID:" + NAVI_GROUP_ID);
        return NAVI_GROUP_ID;
    }

    public int getVoiceGroupId() {
        LogUtils.d(TAG, "getVoiceGroupId VOICE_GROUP_ID:" + VOICE_GROUP_ID);
        return VOICE_GROUP_ID;
    }

    public int getPhoneGroupId() {
        LogUtils.d(TAG, "getPhoneGroupId PHONE_GROUP_ID:" + PHONE_GROUP_ID);
        return PHONE_GROUP_ID;
    }

    public int getMediaMaxVolume() {
        LogUtils.d(TAG, "getMediaMaxVolume MEDIA_MAX_VOLUME:" + MEDIA_MAX_VOLUME);
        return MEDIA_MAX_VOLUME;
    }

    public int getNaviMaxVolume() {
        LogUtils.d(TAG, "getNaviMaxVolume NAVI_MAX_VOLUME:" + NAVI_MAX_VOLUME);
        return NAVI_MAX_VOLUME;
    }

    public int getVoiceMaxVolume() {
        LogUtils.d(TAG, "getVoiceMaxVolume VOICE_MAX_VOLUME:" + VOICE_MAX_VOLUME);
        return VOICE_MAX_VOLUME;
    }

    public int getPhoneMaxVolume() {
        LogUtils.d(TAG, "getPhoneMaxVolume PHONE_MAX_VOLUME:" + PHONE_MAX_VOLUME);
        return PHONE_MAX_VOLUME;
    }

    public static CarVoiceController getCarVoiceController() {
        return mCarVoiceController;
    }

    public CarAudioManager getCarAudioManager() {
        return mCarAudioManager;
    }

    public static synchronized void initCar() {
        if (mCarVoiceController == null) {
            mCarVoiceController = new CarVoiceController();
        }
    }

    private CarVoiceController() {
        initConnect();
        initAudioSource();
        LogUtils.d(TAG, "initConnect ok");
    }


    private void initConnect() {
        Context hostAppContext = PluginContext.getContextByActThread();
        if (hostAppContext == null) {
            LogUtils.e(TAG, "hostAppContext is null");
            return;
        }
        LogUtils.d(TAG, "createCar...");
        mCar = Car.createCar(hostAppContext, serviceConnection);
        if (mCar == null) {
            LogUtils.e(TAG, "createCar is error");
            return;
        }
        try {
            mCar.connect();
        } catch (IllegalStateException exception) {
            LogUtils.e(TAG, " Car connect error : " + exception);
        }
    }

    final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogUtils.d(TAG, "onServiceConnected");
            mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
            if (mCarAudioManager == null) {
                LogUtils.e(TAG, "onServiceConnected , but the mCarAudioManager is null");
                return;
            }
            mCarAudioManager.registerCarVolumeCallback(carVolumeCallback);
            initVoiceInfo(mCarAudioManager);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            LogUtils.e(TAG, "onServiceDisconnected");
            if (mCarAudioManager != null) {
                mCarAudioManager.unregisterCarVolumeCallback(carVolumeCallback);
            }
        }
    };

    @SuppressLint("InlinedApi")
    private void initVoiceInfo(CarAudioManager mCarAudioManager) {
        MEDIA_GROUP_ID = mCarAudioManager.getVolumeGroupIdForUsage(AudioAttributes.USAGE_MEDIA);
        NAVI_GROUP_ID = mCarAudioManager.getVolumeGroupIdForUsage(AudioAttributes.
                USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
        VOICE_GROUP_ID = mCarAudioManager.getVolumeGroupIdForUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY);
        PHONE_GROUP_ID = mCarAudioManager.getVolumeGroupIdForUsage(AudioAttributes.
                USAGE_VOICE_COMMUNICATION);

        MEDIA_MAX_VOLUME = mCarAudioManager.getGroupMaxVolume(MEDIA_GROUP_ID);
        NAVI_MAX_VOLUME = mCarAudioManager.getGroupMaxVolume(NAVI_GROUP_ID);
        VOICE_MAX_VOLUME = mCarAudioManager.getGroupMaxVolume(VOICE_GROUP_ID);
        PHONE_MAX_VOLUME = mCarAudioManager.getGroupMaxVolume(PHONE_GROUP_ID);

        LogUtils.d(TAG, "initVoiceInfo : " +
                "MEDIA_GROUP_ID=" + MEDIA_GROUP_ID + " -MEDIA_MAX_VOLUME:" + MEDIA_MAX_VOLUME +
                ",  NAVI_GROUP_ID=" + NAVI_GROUP_ID + " -NAVI_MAX_VOLUME:" + NAVI_MAX_VOLUME +
                ",  VOICE_GROUP_ID=" + VOICE_GROUP_ID + " -VOICE_MAX_VOLUME:" + VOICE_MAX_VOLUME +
                ",  PHONE_GROUP_ID=" + PHONE_GROUP_ID + " -PHONE_MAX_VOLUME:" + PHONE_MAX_VOLUME);
    }

    final CarAudioManager.CarVolumeCallback carVolumeCallback =
            new CarAudioManager.CarVolumeCallback() {
                @Override
                public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
                    super.onGroupVolumeChanged(zoneId, groupId, flags);
                    LogUtils.d(TAG, "onGroupVolumeChanged zoneId:" + zoneId +
                            ", groupId:" + groupId + ", flags:" + flags);
                    if (mListener != null) {
                        mListener.onGroupVolumeChanged();
                    }

                }

                @Override
                public void onGroupMuteChanged(int zoneId, int groupId, int flags) {
                    super.onGroupMuteChanged(zoneId, groupId, flags);
                    LogUtils.d(TAG, "onGroupMuteChanged zoneId:" + zoneId +
                            ", groupId:" + groupId + ", flags:" + flags);
                    //全局静音 需要修改状态栏图标
                    if (mListener != null) {
                        mListener.onGroupMuteChanged();
                    }
                }

                @Override
                public void onMasterMuteChanged(int zoneId, int flags) {
                    super.onMasterMuteChanged(zoneId, flags);
                    LogUtils.d(TAG, "onMasterMuteChanged zoneId:" + zoneId +
                            ", flags:" + flags);

                }
            };


    /**
     * 获取是否全局静音
     */
    public boolean isStreamMuteAll() {
        if (mCarAudioManager != null && mAudioSource != null && mAudioSource.size() > 0) {
            for (Integer streamType : mAudioSource) {
                int groupId = getGroupIdByStreamType(streamType);
                boolean streamMute = mCarAudioManager.getGroupVolume(0, groupId) <= 0;
                LogUtils.d(TAG,"isStreamMuteAll 是否静音 -- streamMute:" + streamMute + "--streamType:" + streamType);
                if (!streamMute) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    private void initAudioSource() {
        if (mAudioSource == null) {
            mAudioSource = new ArrayList<>();
            //多媒体
            mAudioSource.add(STREAM_MUSIC);
            //导航音量
            mAudioSource.add(STREAM_NAVI_TTS);
            //语音助手
            mAudioSource.add(STREAM_ASSISTANT);
            //通话音量
            mAudioSource.add(STREAM_VOICE_CALL);
        }
    }

    public void setStreamMuteAll(boolean isMute) {
        for (Integer streamType : mAudioSource) {
            int groupId = getGroupIdByStreamType(streamType);
            mCarAudioManager.setGroupVolume(groupId, 0, isMute? ADJUST_MUTE : ADJUST_UNMUTE);
            LogUtils.d(TAG,"setStreamMuteAll isMute: " + isMute + ", groupId = " + groupId);
        }
    }

    public int getGroupIdByStreamType(int streamType) {
        AudioAttributes aa = new AudioAttributes.Builder().setLegacyStreamType(streamType).build();
        int groupId = mCarAudioManager.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, aa.getUsage());
        return groupId;
    }

    public int getGlobalMaxVolume(int curGroupId) {
        int volume = mCarAudioManager.getGroupMaxVolume(curGroupId);
        return volume;
    }



    private int getSteamTypeByUsage(int currentUsage) {
        int streamType = STREAM_MUSIC;
        switch (currentUsage) {
            case AudioAttributes.USAGE_VOICE_COMMUNICATION: //PHONE_GROUP_ID
                streamType = STREAM_VOICE_CALL;
                break;
            case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: //VOICE_GROUP_ID
                streamType = STREAM_ASSISTANT;
                break;
            case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: //NAVI_GROUP_ID
                streamType = STREAM_NAVI_TTS;
                break;
            case AudioAttributes.USAGE_MEDIA: //MEDIA_GROUP_ID
                streamType = STREAM_MUSIC;
                break;
            default:
                break;
        }
        return streamType;
    }


    public boolean isStreamMuteCurrent(int curUsage) {
        //CSD传0 PSD传1
        int groupId = mCarAudioManager.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, curUsage);
        return mCarAudioManager.getGroupVolume(0, groupId) <= 0;
    }

    public boolean isStreamMute(int streamType) {
        int groupId = getGroupIdByStreamType(streamType);
        return mCarAudioManager.getGroupVolume(0, groupId) <= 0;
    }


    public interface IOnVolumeChanged {
        void onGroupMuteChanged();
        void onGroupVolumeChanged();
    }
    public void setOnVolumeChanged(IOnVolumeChanged listener) {
        mListener = listener;
    }
}
